const fs = require('fs')
const axios = require("axios");
const { parser } = require('stream-json');
const { streamArray } = require('stream-json/streamers/StreamArray');
const AdmZip = require('adm-zip');


/**
 * 下载文件
 * @param {*} saveFilePath 
 * @param {*} downloadUrl 
 * @returns 
 */
const downloadByUrl = (saveFilePath, downloadUrl) => {
    return new Promise((resolve, reject) => {
        axios({
            method: 'get',
            url: downloadUrl,
            responseType: 'stream'
        }).then(response => {
            const writer = fs.createWriteStream(saveFilePath);
            // 管道传输
            response.data.pipe(writer);
            // 成功完成
            writer.on('finish', () => {
                // 确保文件句柄完全关闭
                writer.close(() => {
                    resolve(saveFilePath);
                })
            });
            // 写入错误
            writer.on('error', (err) => {
                reject(new Error(`文件写入失败: ${err.message}`));
            });
        }).catch(err => {
            reject(new Error(`下载失败: ${err.message}`))
        });
    })
}


/**
 * 读取json文件流，并分页返回数据
 * @param {*} jsonPath 
 * @param {*} page 
 * @param {*} pageSize 
 * @param {*} columnFieldTotal 
 * @returns 
 */
const streamPageFromJson = (jsonPath, page = 1, pageSize = 100, needTotalNum = false, columnFieldTotal = {}) => {
    return new Promise((resolve, reject) => {
        const startIndex = (page - 1) * pageSize;
        const endIndex = startIndex + pageSize;
        const resultPage = [];
        let totalCount = 0;
        let needTotal = needTotalNum; // 只在第一页时需要计算总数
        let streamEnded = false; // 标记流是否已经结束
        const stream = fs.createReadStream(jsonPath)
            .pipe(parser())
            .pipe(streamArray());

        // 创建一个函数来结束流并返回结果
        const endStreamAndResolve = () => {
            if (!streamEnded) {
                streamEnded = true;
                stream.destroy();
                // 如果不是第一页，我们可能不知道确切的总数，但可以估算
                const estimatedTotal = needTotal ? totalCount : (page * pageSize * 2); // 估算值
                resolve({
                    page,
                    pageSize,
                    total: estimatedTotal,
                    totalPages: Math.ceil(estimatedTotal / pageSize),
                    data: resultPage,
                    columnFieldTotal: columnFieldTotal
                });
            }
        };
        stream.on('data', ({ value }) => {
            totalCount++;
            // 如果需要计算总数，并且 columnFieldTotal 是一个对象，并且对象的属性长度大于0
            if (needTotal && typeof columnFieldTotal === 'object' && Object.keys(columnFieldTotal).length > 0) {
                for (const field in columnFieldTotal) {
                    columnFieldTotal[field] += value[field] || 0;
                }
            }
            // 分页逻辑
            if (totalCount > startIndex && totalCount <= endIndex) {
                resultPage.push(value);
                // 如果已经收集了足够的数据（达到了页大小），并且不需要计算总数（非第一页）
                if (resultPage.length === pageSize && !needTotal) {
                    endStreamAndResolve();
                    return;
                }
            } else if (totalCount > endIndex && !needTotal) {
                // 如果已经超过了结束索引，并且不需要计算总数（非第一页），可以结束流
                endStreamAndResolve();
                return;
            }
        });

        stream.on('end', () => {
            if (!streamEnded) {
                endStreamAndResolve();
            }
        });

        stream.on('error', (err) => {
            if (!streamEnded) {
                streamEnded = true;
                reject(err);
            }
        });
    });
}


/**
 * 解压文件
 * @param {*} zipPath 
 * @param {*} saveFilePath 
 * @returns 
 */
const unzipSync = (zipPath, saveFilePath) => {
    try {
        const zip = new AdmZip(zipPath);
        zip.extractAllTo(saveFilePath);
    } catch (err) {
        throw new Error('解压失败:' + err.message);
    }
}

module.exports = {
    downloadByUrl,
    unzipSync,
    streamPageFromJson
}